-- 自动打魔眼
-- 失败了，暂时不写了，原因：魔眼二阶段来回冲撞是随机时间发生的，从检测到动画的那一刻开始躲避就已经晚了


-- 用来debug的代码
-- ents = TheSim:FindEntities(ThePlayer:GetPosition().x, 0, ThePlayer:GetPosition().z, 50) 
-- for k,v in pairs(ents)do 
--     if v.prefab == "eyeofterror_mini_grounded" or v.prefab == "eyeofterror_mini" and v.components and v.components.health then 
--         v.components.health:Kill() 
--     end 
-- end
local SendRPCToServer = GLOBAL.SendRPCToServer
local RPC = GLOBAL.RPC
local ACTIONS = GLOBAL.ACTIONS
local TUNING = GLOBAL.TUNING
local BossAtkRange = TUNING.EYEOFTERROR_ATTACK_RANGE + 2
local KEY = false
local boss_list = {"eyeofterror", "twinofterror1", "twinofterror2"}
local PlayerSpeed = 6

local function playerStop()
    SendRPCToServer(RPC.StopWalking)
    SendRPCToServer(RPC.StopControl, ACTIONS.ABANDON_QUEST.code)
    SendRPCToServer(RPC.ClearActionHold)
    SendRPCToServer(RPC.StopControl)
end

local function ShowTIP(info, color)
    if not color then color = "red" end
    TIP("走位魔眼", color, info, "chat")
end

local last_boss_atkpre, last_boss_atkpst= 0,0
local anim_reset_time = 1.6
local boss_position_fixed,boss_position_moved
local waitstate = true
local attack_target
local search_range = 10
local upgrade,deathstate = false,false
local clicked = false
local current_target

local function reset()
    KEY = false
    playerStop()
    upgrade = false
    deathstate = false
    current_target = nil
end


for _,boss_name in pairs(boss_list)do
    AddPrefabPostInit(boss_name, function(inst)
        local player = GLOBAL.ThePlayer
        inst:DoPeriodicTask(GLOBAL.FRAMES, function()
            if KEY and inst == current_target then
                local nowtime = GLOBAL.GetTime()
                if inst and inst.AnimState then
                    if c_anim("charge_pre", inst) then
                        if nowtime - last_boss_atkpre > anim_reset_time then
                            last_boss_atkpre = nowtime
                            boss_position_fixed = inst:GetPosition()
                            boss_position_moved = nil
                        end
                    elseif c_anim("charge_pst", inst) then
                        if nowtime - last_boss_atkpst > anim_reset_time then
                            last_boss_atkpst = nowtime
                            boss_position_fixed = inst:GetPosition()
                            boss_position_moved = nil
                        end
                    elseif c_anim("charge_loop", inst) then
                        if nowtime - last_boss_atkpst < 0.1 or nowtime - last_boss_atkpre < 0.1 then
                            boss_position_moved = inst:GetPosition()
                        end
                    elseif c_anim({"transform", "spawn2_loop", "spawn2_pre"}, inst) then
                        -- 事实上这不是一种很好的办法, 可惜AnimState没有某个部件的IsVisible()方法
                        upgrade = true
                    elseif c_anim("death", inst) then
                        deathstate = true
                    end
                end
                if player then
                    local mobiletime = BossAtkRange / PlayerSpeed
                    local shouldleave =  
                        nowtime - last_boss_atkpre  < mobiletime                -- 预备攻击
                        or (nowtime - last_boss_atkpst < mobiletime and upgrade)
                    if shouldleave and GetAggro(inst) == player then
                        waitstate = false
                        SendRPCToServer(RPC.DirectWalking, GetDirectionAToB({x = boss_position_fixed.x, z = boss_position_fixed.z}, boss_position_moved or player:GetPosition(), "left"))
                    end
                    if not shouldleave and not waitstate then
                        waitstate = true
                        SendRPCToServer(RPC.StopWalking)
                        attack_target = nil
                    end
                    if waitstate then
                        if attack_target and attack_target:IsValid() and not c_anim({"death", "land_break"}, attack_target) then
                            if not clicked then
                                local pos = attack_target:GetPosition()
                                SendRPCToServer(RPC.LeftClick, ACTIONS.ATTACK.code, pos.x, pos.z, attack_target, nil, nil, true, nil, nil, false)
                                clicked = true
                            else
                                SendRPCToServer(RPC.RepeatHeldAction)
                            end
                        else
                            clicked = false
                            SendRPCToServer(RPC.ClearActionHold)
                            SendRPCToServer(RPC.StopControl)
                            attack_target = PlayerFindEnt({"eyeofterror_mini_grounded", "eyeofterror_mini"}, search_range, nil, nil, nil, {"death", "land_break"})
                            if not attack_target then
                                attack_target = PlayerFindEnt(inst.prefab, 8*search_range)
                                if not attack_target and deathstate then
                                    ShowTIP("结束啦！","green")
                                    attack_target = PlayerFindEnt({"eyeofterror_mini_grounded", "eyeofterror_mini"}, 8*search_range, nil, nil, nil, {"death", "land_break"})
                                    if not attack_target then
                                        reset()
                                        ShowTIP("完成！","green")
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end)
    end)
end


local function fn_alt()
    if not KEY then
        current_target = PlayerFindEnt(boss_list, 10*search_range, nil, nil, nil, "death")
        if current_target then
            ShowTIP("已开启, 请装备好武器和头盔, 当前目标:"..current_target.name , "green")
            upgrade = false
            KEY = true
            GLOBAL.ThePlayer:EnableMovementPrediction(true)
            if GLOBAL.ThePlayer.components.locomotor then
                PlayerSpeed = GLOBAL.ThePlayer.components.locomotor:GetSpeedMultiplier()*GLOBAL.ThePlayer.components.locomotor:GetRunSpeed()
                if PlayerSpeed ~= 6 then
                    ShowTIP("请确保人物移速稳定")
                end
            end
            GLOBAL.ThePlayer:EnableMovementPrediction(false)
            local pingN = GLOBAL.TheNet:GetAveragePing()
            if pingN >= 60 then
                ShowTIP("当前延迟较大("..tostring(pingN).."ms), 走位可能频繁失败")
            end
        else
            ShowTIP("未发现魔眼")
        end
    else
        KEY = false
        ShowTIP('关闭')
    end
end


local function fn()
    local boss = PlayerFindEnt(boss_list)
    local player = GLOBAL.ThePlayer
    if boss and player then
        local boss_pos = boss:GetPosition()
        if math.sqrt(boss_pos:DistSq(player:GetPosition())) < 36*36 then
            SendRPCToServer(RPC.RightClick, ACTIONS.BLINK.code, boss_pos.x, boss_pos.z, nil, nil, nil, nil, nil, nil, nil, false)
            TIP("传送坐标","green", string.format("x: %.2f, y: %.2f", boss_pos.x, boss_pos.z), "chat")
        else
            SendRPCToServer(RPC.DoActionOnMap, ACTIONS.BLINK_MAP.code, boss_pos.x, boss_pos.z)
            TIP("地图传送","green", string.format("x: %.2f, y: %.2f", boss_pos.x, boss_pos.z), "chat")
        end
    end
end
local NEW_KEY
local function Load()
    local PlayerController = GLOBAL.ThePlayer and GLOBAL.ThePlayer.components.playercontroller

    if not PlayerController then
        return
    end

    local OldGetAttackTarget = PlayerController.GetAttackTarget
    function PlayerController:GetAttackTarget(...)
        local force_target = OldGetAttackTarget(self, ...)

        if NEW_KEY and force_target and table.contains(boss_list, force_target.prefab) then
            local eye_mini = PlayerFindEnt({"eyeofterror_mini_grounded", "eyeofterror_mini"}, 2, nil, nil, nil, {"death", "land_break"})
            if eye_mini then
                TIP("重定向目标","green", eye_mini.name, "chat")
                return eye_mini
            end
        end

        return force_target
    end
end


local function OnWorldPostInit(inst)
    inst:ListenForEvent("playeractivated", Load, GLOBAL.TheWorld)
end
AddPrefabPostInit("world", OnWorldPostInit)


local function init()
    if GLOBAL.TheInput:IsKeyDown(GLOBAL.KEY_LALT) then
        fn_alt()
    else
        fn()
        NEW_KEY = true
    end
end


DEAR_BTNS:AddDearBtn(GLOBAL.GetInventoryItemAtlas("critter_eyeofterror_builder.tex"), "critter_eyeofterror_builder.tex", "测试魔眼", "【测试功能，请勿开启】", true, init)